package com.lanyou.esb.cook.proxy.auth.processor.impl;

import java.util.Calendar;
import java.util.Date;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;

import com.lanyou.esb.cook.proxy.auth.processor.VerifyAuthProcessor;
import com.lanyou.esb.cook.proxy.common.Constants;
import com.lanyou.esb.cook.proxy.common.SystemResCode;
import com.lanyou.esb.cook.proxy.entity.FieldSystem;
import com.lanyou.esb.cook.proxy.entity.Http;
import com.lanyou.esb.cook.proxy.entity.Token;
import com.lanyou.esb.cook.proxy.exception.AuthException;
import com.lanyou.esb.cook.proxy.meta.AuthType;
import com.lanyou.esb.cook.proxy.meta.Environment;
import com.lanyou.esb.cook.proxy.service.impl.TraceLogServiceImpl;

/**
 * OAUTH验证权限处理接口
 * 
 * @author Davey.wu
 */
public class OauthVerifyAuthProcessor implements VerifyAuthProcessor {

	@Override
	public AuthType getAuthType() {
		return AuthType.OAUTH;
	}

	@Override
	public boolean verify(FieldSystem system, Http http,
			Map<String, Object> map, Token token) throws Exception {
		// 校验信息为空
		if (map == null || map.isEmpty()) {
			throw new AuthException(SystemResCode.MSG_AUTHINFO_EMPTY,
					SystemResCode.CODE_AUTHINFO_EMPTY);
		}
		// 获取访问令牌
		String accessToken = (String) map.get(Constants.ACCESS_TOKEN);
		// 获取调用方系统编码
		String callSystemCode = (String) map.get(Constants.CALL_SYSTEM_CODE);
		// 调用方系统编码不能为空
		if (StringUtils.isBlank(callSystemCode)) {
			throw new AuthException(SystemResCode.MSG_CALL_SYSTEM_EMPTY,
					SystemResCode.CODE_CALL_SYSTEM_EMPTY);

		}
		// 访问令牌不能为空
		if (StringUtils.isBlank(accessToken)) {
			throw new AuthException(SystemResCode.MSG_ACCESSTOKEN_EMPTY,
					SystemResCode.CODE_ACCESSTOKEN_EMPTY);
		}

		boolean result = false;
		Environment environment = (Environment) map.get(Constants.ENVIRONMENT);
		switch (environment) {
		case PRODUCTION:
			// 正式环境
			result = verify(system.getCode(), callSystemCode, http,
					accessToken, token);
			break;
		case TEST:
			// 测试环境
			result = verifyTestEnvironment(system.getCode(), callSystemCode,
					http, accessToken, token);
			break;
		default:
			return false;
		}

		// TODO need do other things?
		return result;
	}

	/**
	 * 服务测试，令牌信息校验
	 * 
	 * @param systemCode
	 *            ：系统编码
	 * @param callSystemCode
	 *            ：调用方系统编码
	 * @param http
	 *            ：接口
	 * @param accessToken
	 *            ：访问令牌
	 * @return
	 * @throws Exception
	 */
	private boolean verifyTestEnvironment(String systemCode,
			String callSystemCode, Http http, String accessToken, Token token)
			throws Exception {
		if (token == null) {
			throw new AuthException(SystemResCode.MSG_TOKEN_NOT_FOUND,
					SystemResCode.CODE_TOKEN_NOT_FOUND);
		}
		// 判断访问令牌是否正确
		if (!accessToken.equals(token.getAccessToken())) {
			throw new AuthException(SystemResCode.MSG_ACCESSTOKEN_INVALID,
					SystemResCode.CODE_ACCESSTOKEN_INVALID);
		}
		return true;
	}

	/**
	 * 访问令牌信息校验
	 * 
	 * @param systemCode
	 *            ：系统编码
	 * @param callSystemCode
	 *            ：调用方系统编码
	 * @param http
	 *            ：接口
	 * @param accessToken
	 *            ：访问令牌
	 * @return
	 * @throws Exception
	 */
	private boolean verify(String systemCode, String callSystemCode, Http http,
			String accessToken, Token token) throws Exception {
		if (TraceLogServiceImpl.isTrace()) {
			// 记录跟踪日志
			TraceLogServiceImpl
					.addTraceLog(Constants.MSG_BEGIN_ACCESSTOKEN_INFO);
		}
		// 令牌为空
		if (token == null) {
			if (TraceLogServiceImpl.isTrace()) {
				// 记录跟踪日志
				TraceLogServiceImpl.addTraceLog(
						SystemResCode.MSG_TOKEN_NOT_FOUND,
						Constants.FLAG_LEFT_SQUARE_BRACKET,
						Constants.SYSTEM_CODE, Constants.FLAG_EQUAL,
						systemCode, Constants.FLAG_COMMA_SYMBOL,
						Constants.CALL_SYSTEM_CODE, Constants.FLAG_EQUAL,
						callSystemCode, Constants.FLAG_COMMA_SYMBOL,
						Constants.INTERFACE_CODE, Constants.FLAG_EQUAL,
						(http == null ? "" : http.getCode()),
						Constants.FLAG_COMMA_SYMBOL,
						Constants.INTERFACE_VERSION, Constants.FLAG_EQUAL,
						(http == null ? "" : http.getVersion()),
						Constants.FLAG_RIGHT_SQUARE_BRACKET);
			}
			throw new AuthException(SystemResCode.MSG_TOKEN_NOT_FOUND,
					SystemResCode.CODE_TOKEN_NOT_FOUND);
		}
		// 密钥有效期丢失
		if (token.getKeyInvalidDate() == null) {
			if (TraceLogServiceImpl.isTrace()) {
				// 记录跟踪日志
				TraceLogServiceImpl.addTraceLog(
						SystemResCode.MSG_APPLYKEY_EXPIRESIN_EMPTY,
						Constants.FLAG_LEFT_SQUARE_BRACKET,
						Constants.MSG_APPLY_KEY_INVALID_DATE,
						Constants.FLAG_EQUAL, Constants.NULL_VALUE,
						Constants.FLAG_RIGHT_SQUARE_BRACKET);
			}

			throw new AuthException(SystemResCode.MSG_APPLYKEY_EXPIRESIN_EMPTY,
					SystemResCode.CODE_APPLYKEY_EXPIRESIN_EMPTY);
		}
		Date now = new Date();
		// 密钥过期
		if (now.after(token.getKeyInvalidDate())) {
			if (TraceLogServiceImpl.isTrace()) {
				// 记录跟踪日志
				TraceLogServiceImpl.addTraceLog(
						SystemResCode.MSG_APPLYKEY_EXPIRED,
						Constants.FLAG_LEFT_SQUARE_BRACKET,
						Constants.MSG_APPLY_KEY_INVALID_DATE,
						Constants.FLAG_EQUAL, token.getKeyInvalidDate()
								.toLocaleString(), Constants.FLAG_COMMA_SYMBOL,
						Constants.MSG_CURRENT_TIME, Constants.FLAG_EQUAL, now
								.toLocaleString(),
						Constants.FLAG_RIGHT_SQUARE_BRACKET);
			}

			throw new AuthException(SystemResCode.MSG_APPLYKEY_EXPIRED,
					SystemResCode.CODE_APPLYKEY_EXPIRED);
		}
		// 访问令牌缺失
		if (StringUtils.isBlank(accessToken)
				|| StringUtils.isBlank(token.getAccessToken())) {
			if (TraceLogServiceImpl.isTrace()) {
				// 记录跟踪日志
				TraceLogServiceImpl.addTraceLog(
						SystemResCode.MSG_ACCESSTOKEN_EMPTY,
						Constants.FLAG_LEFT_SQUARE_BRACKET,
						Constants.ACCESS_TOKEN, Constants.FLAG_EQUAL,
						accessToken, Constants.FLAG_RIGHT_SQUARE_BRACKET);
			}
			throw new AuthException(SystemResCode.MSG_ACCESSTOKEN_EMPTY,
					SystemResCode.CODE_ACCESSTOKEN_EMPTY);
		}
		// 访问令牌不正确
		if (accessToken.compareTo(token.getAccessToken()) != 0) {
			if (TraceLogServiceImpl.isTrace()) {
				// 记录跟踪日志
				TraceLogServiceImpl.addTraceLog(
						SystemResCode.MSG_ACCESSTOKEN_INVALID,
						Constants.FLAG_LEFT_SQUARE_BRACKET,
						Constants.ACCESS_TOKEN, Constants.FLAG_EQUAL,
						accessToken, Constants.FLAG_RIGHT_SQUARE_BRACKET);
			}
			throw new AuthException(SystemResCode.MSG_ACCESSTOKEN_INVALID,
					SystemResCode.CODE_ACCESSTOKEN_INVALID);
		}
		// 访问令牌申请日期为空
		if (null == token.getApplyDate()) {
			if (TraceLogServiceImpl.isTrace()) {
				// 记录跟踪日志
				TraceLogServiceImpl.addTraceLog(
						SystemResCode.MSG_APPLYDATE_EMPTY,
						Constants.FLAG_LEFT_SQUARE_BRACKET,
						Constants.APPLY_DATE, Constants.FLAG_EQUAL,
						Constants.NULL_VALUE,
						Constants.FLAG_RIGHT_SQUARE_BRACKET);
			}
			throw new AuthException(SystemResCode.MSG_APPLYDATE_EMPTY,
					SystemResCode.CODE_APPLYDATE_EMPTY);
		}
		// 访问令牌有效期丢失
		if (token.getInvalidTimes() <= 0) {
			if (TraceLogServiceImpl.isTrace()) {
				// 记录跟踪日志
				TraceLogServiceImpl.addTraceLog(
						SystemResCode.MSG_ACCESSTOKEN_EXPIRESIN_EMPTY,
						Constants.FLAG_LEFT_SQUARE_BRACKET,
						Constants.INVALID_TIMES, Constants.FLAG_EQUAL,
						token.getInvalidTimes() + "",
						Constants.FLAG_RIGHT_SQUARE_BRACKET);
			}
			throw new AuthException(
					SystemResCode.MSG_ACCESSTOKEN_EXPIRESIN_EMPTY,
					SystemResCode.CODE_ACCESSTOKEN_EXPIRESIN_EMPTY);
		}

		Calendar calendar = Calendar.getInstance();
		calendar.setTime(token.getApplyDate());
		calendar.add(Calendar.SECOND, token.getInvalidTimes());
		// 访问令牌过期时间
		Date expiredDate = calendar.getTime();
		// 当前时间
		Date systemDate = new Date();
		// the access_token is expired
		if (systemDate.after(expiredDate)) {
			if (TraceLogServiceImpl.isTrace()) {
				// 记录跟踪日志
				TraceLogServiceImpl.addTraceLog(
						SystemResCode.MSG_ACCESSTOKEN_EXPIRED,
						Constants.FLAG_LEFT_SQUARE_BRACKET,
						Constants.EXPIRED_DATE, Constants.FLAG_EQUAL,
						expiredDate.toLocaleString(),
						Constants.FLAG_COMMA_SYMBOL, Constants.CURRENT_DATE,
						Constants.FLAG_EQUAL, systemDate.toLocaleString(),
						Constants.FLAG_RIGHT_SQUARE_BRACKET);
			}
			throw new AuthException(SystemResCode.MSG_ACCESSTOKEN_EXPIRED,
					SystemResCode.CODE_ACCESSTOKEN_EXPIRED);
		}
		return true;
	}

}
